{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# MAML Algorithm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have a basic understanding of MAML, we explore more about them in detail. Let us say we have a model $f$ parameterized by $\\theta$ i.e $f_{\\theta}()$ and we have a distribution over tasks $p(T) $. First, we initialize our parameter  $\\theta$ with some random values. Next, we sample some batch of tasks $T_i$ from a distribution over tasks. i.e .$T_i \\sim p(T)$. Let us say we have sampled tasks 5 tasks, $T = \\{{ T_1, T_2, T_3,T_4,T_5} \\} $  then for each task $T_i$ we sample K data points and train the model. We train the model by computing the loss  $L_{T_i}(f_{\\theta})$ and we minimize the loss using gradient descent and find the optimal set of parameters that minimize the loss. i.e, \n",
    "\n",
    "\n",
    "$\\theta'_i = \\theta - \\alpha \\nabla_{\\theta} L_{T_i}(f_{\\theta}) $"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "where,\n",
    "\n",
    "$\\theta'_i$ the optimal parameter for a task $T_i$\n",
    "\n",
    "$\\theta$ is the initial parameter\n",
    "\n",
    "$\\alpha$ is the hyperparameter\n",
    "\n",
    "$\\nabla_{\\theta} L_{T_i}(f_{\\theta})$ is the gradient of a task $T_i$ . \n",
    "\n",
    "So after the above gradient update, we will have optimal parameters $\\theta'$ for all the five tasks which we have sampled i.e. $\\theta' =\\{ {\\theta'_1, \\theta'_2, \\theta'_3, \\theta'_4, \\theta'_5}\\} $"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, before sampling the next batch of tasks, we perform meta update or meta optimization. i.e In the previous step, we found the optimal parameter $\\theta'_i$ by training on each of the tasks $T_i$ . Now we calculate gradient with respect to these optimal parameters $\\theta'_i$ and update our randomly initialized parameter $\\theta$ by training on a new set of tasks $T_i$. This makes us our randomly initialized parameter $\\theta$ to move to an optimal position where we don't have to take many gradient steps while training on the next batch of tasks. This step is called meta step or meta update or meta optimization or meta training. It can be expressed as,\n",
    "\n",
    "$\\theta = \\theta - \\beta \\nabla_{\\theta} \\sum_{T_i \\sim p(T)} L_{T_i}(f_{\\theta_i}) $"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "where ,\n",
    "\n",
    "$\\theta$ is our initial parameter\n",
    "\n",
    "$\\beta$ is the hyperparameter\n",
    "\n",
    "$\\nabla_{\\theta} \\sum_{T_i \\sim p(T)} L_{T_i}(f_{\\theta_i})$  is the gradient for each of the new task  $T_i$ with respect to parameter $\\theta_i'$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "if you look at our above meta update equation closely, we can notice that we are updating our model parameter $\\theta$ by merely taking an average of gradients of each new task $T_i$ with optimal parameter  $\\theta_i'$. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The overall algorithm of MAML is shown in the below figure, our algorithm consists of two loops, inner loop where we find the optimal parameter $\\theta_i'$ for each of the task  $T_i$ and outer loop where we update our randomly initialized model parameter $\\theta$  by calculating gradients with respect to the optimal parameters  $\\theta_i'$. in a new set of tasks $T_i$. __We should always remember that we should not use the same set of tasks $T_i$  with which we find the optimal parameter $\\theta_i'$  while updating the model parameter $\\theta$  in the outer loop. __"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![title](Images/3.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So, in a nutshell, in MAML, we sample some batch of task and for each task $T_i$ in the batch, we minimize the loss using gradient descent and get the optimal parameter $\\theta_i' $. Then before sampling another batch of tasks, we update our randomly initialized model parameter $\\theta$ by calculating gradients with respect to the optimal parameters $\\theta_i' $  in a new set of tasks $T_i$. \n",
    "\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [default]",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
